using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Win32;
using System.Diagnostics;
using System.Runtime.Remoting;
using EasyHook;
using System.IO;

namespace HoldemHook
{


    /*
        * This is the class where our clients will connect to!
        * 
        * Please note that setting any breakpoint here will cause the related
        * thread in the client process to block until you continue execution!
        * So don't wonder if your browser (for example) hangs when you set a 
        * breakpoint ;-)... Let's say you can debug a part of the code the client
        * is executing (that's not technically correct)
        * 
        * In Windows 2000 debugging the following seems to cause problems. 
        */
    public class InjectClient : MarshalByRefObject
    {
        protected static EventHandler<CallEventArgs> _callEvent;
        protected static EventHandler<WindowEventArgs> _wndEvent;
        protected static EventHandler<GUINodeEventArgs> _guiNodeEvent;

        public static InjectClient Instance = null;
        public static Int32 TargetPID = 0;

        public static int ConstrCallCount = 0;

        public static string ChannelName = null;

        public static TextWriter log;

        public static TextWriter Log {
            get
            {
                if (null == log)
                    log = new StreamWriter("InjectClient.log");
                return log;
            }
        }

        public static bool ShowMsgBox = false;

        public static event EventHandler<CallEventArgs> InjectEvent
        {
            add { _callEvent += value; }
            remove { _callEvent -= value; }
        }

        public static event EventHandler<WindowEventArgs> WindowEvent
        {
            add { _wndEvent += value; }
            remove { _wndEvent -= value; }
        }

        public static event EventHandler<GUINodeEventArgs> GUINodeEvent
        {
            add { _guiNodeEvent += value; }
            remove { _guiNodeEvent -= value; }
        }
        public void ReportError(
            Int32 InClientPID,
            Exception e)
        {
            string msg = string.Format("PID={0}; Error: {1}", InClientPID, e);
            if (ShowMsgBox)
                MessageBox.Show(msg);
            if (null != Log)
                Log.WriteLine("{0}: {1}", DateTime.Now, msg);
        }

        public InjectClient()
        {
        }
        public bool Ping(Int32 InClientPID)
        {
            /*
             * We should just check if the client is still in our list
             * of hooked processes...
             
            lock (Form1.ProcessList)
            {
                return Form1.HookedProcesses.Contains(InClientPID);
            }*/
            return TargetPID==InClientPID;
        }

        public void FireCallEvent(CallEventArgs args)
        {
            if(null!=Log)
                Log.WriteLine("CALL: {0}",args);
            try
            {
                if (null != _callEvent)
                    _callEvent(null, args);
            }
            catch (Exception e)
            {
                Log.WriteLine("EXCEPTION: {0}", e);
                MessageBox.Show(e.ToString());
            }
        }

        public void FireGUINodeEvent(GUINodeEventArgs args)
        {
            if (null != Log)
                Log.WriteLine("GUINODE: {0}", args);
            try
            {
                if (null != _guiNodeEvent)
                    _guiNodeEvent(null, args);
            }
            catch (Exception e)
            {
                Log.WriteLine("EXCEPTION: {0}", e);
                MessageBox.Show(e.ToString());
            }
        }


        public void FireWindowEvent(WindowEventArgs args)
        {
            Log.WriteLine("WINDOW: {0}", args.Wnd);
            try
            {
                if (null != _wndEvent)
                    _wndEvent(null, args);
            }
            catch (Exception e)
            {
                Log.WriteLine("EXCEPTION: {0}", e);
                MessageBox.Show(e.ToString());
            }
        }


        public static void Inject(string TargetName, string AppName)
        {
            try
            {
                try
                {
                    Process[] targets = Process.GetProcessesByName(TargetName);
                    if (targets.Length == 0)
                    {
                        MessageBox.Show(String.Format("No {0} process(es) found", TargetName));
                        return;
                    }
                    if (targets.Length > 1)
                    {
                        MessageBox.Show(String.Format("Multiple {0} processes found. Connecting to PID={1}", TargetName, targets[0].Id));
                    }

                    InjectClient.TargetPID = targets[0].Id;

                    EasyHook.Config.Register(
                        TargetName,
                        AppName,
                        "Inject.dll");
                }
                catch (ApplicationException ae)
                {
                    Report(ae);
                    // TODO System.Diagnostics.Process.GetCurrentProcess().Kill();
                    throw ae;
                }

                RemoteHooking.IpcCreateServer<InjectClient>(ref ChannelName, WellKnownObjectMode.SingleCall);

                RemoteHooking.Inject(
                    InjectClient.TargetPID,
                    "Inject.dll",
                    "Inject.dll",
                    ChannelName);
            }
            catch (Exception ExtInfo)
            {
                Report(ExtInfo);
                throw new ApplicationException(string.Format("Error {0}", ExtInfo.Message), ExtInfo);
            }
        }

        static void Report(Exception e)
        {
            string msg = string.Format("Error: {0}",e);
            if (Log != null)
                Log.WriteLine("{0}: {1}",DateTime.Now, msg);
            if (true)
                MessageBox.Show(msg, "Injector", MessageBoxButtons.OK);
        }

    }
}
